package no.sachmuld.methodcombination.api.reflection.component;

import no.sachmuld.methodcombination.impl.AbstractMethodInvocation;
import no.sachmuld.methodcombination.api.BehaviourChain;
import no.sachmuld.methodcombination.api.CrosscuttingBehaviour;

import java.lang.reflect.Method;

/**
 *
 */
public class CrosscuttingAroundMethodCombination<B extends CrosscuttingBehaviour, R> extends DelegatingMethodCombination<B, R> {

    private MethodCombination<B, R> inner;

    public CrosscuttingAroundMethodCombination<B, R> inner(MethodCombination<B, R> inner) {
        this.inner = inner;
        return this;
    }

    @Override
    public CrosscuttingAroundMethodCombination<B, R> build(Class behaviourClass, final Method targetMethod) {

        executedBy(new AbstractMethodCombination<B, R>() {
            @Override
            public R execute(final Object targetObject, final BehaviourChain<? extends B> behaviourChain, final Object... parameters) {
                return new AbstractMethodInvocation<B, R>(behaviourChain.bottomUp(), targetObject, targetMethod, parameters) {
                    @Override
                    protected R executeBehaviour(B behaviour) {
                        return (R) behaviour.around(this);
                    }

                    @Override
                    protected R atEnd() {
                        return inner.execute(targetObject, behaviourChain, parameters);
                    }
                }.execute();
            }
        });

        return this;
    }

}
